package com.amt.olcacon.controller.flow;

import cn.hutool.json.JSONUtil;
import com.amt.olcacon.db.DerbyConfig;
import com.amt.olcacon.vo.GlobalResponse;
import com.amt.olcacon.vo.request.FlowRequest;
import com.amt.olcacon.vo.request.FlowRequestList;
import com.amt.olcacon.vo.request.PropertyFatorsRequest;
import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.openlca.core.DataDir;
import org.openlca.core.database.FlowDao;
import org.openlca.core.model.Flow;
import org.openlca.core.model.FlowProperty;
import org.openlca.core.model.FlowPropertyFactor;
import org.openlca.core.model.Location;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;

/**
 * flow api
 *
 * @Author: yangyusheng
 * @Date: 2025/05/28
 */
@Slf4j
@RestController
@RequestMapping("/olca/flow")
public class FlowController {

    @PostMapping("/add")
    public GlobalResponse<Long> add(@RequestBody FlowRequest request) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        Flow flow = Flow.product(
                request.getName(),
                db.get(FlowProperty.class, request.getFlowPropertyId())
        );

        flow.id = request.getId();
        flow.refId = request.getRefId();
        if (request.getInfrastructureFlow() != null) {
            flow.infrastructureFlow = request.getInfrastructureFlow();
        }
        if (StringUtils.isNotBlank(request.getDescription())) {
            flow.description = request.getDescription();
        }
        if (StringUtils.isNotBlank(request.getCasNumber())) {
            flow.casNumber = request.getCasNumber();
        }
        if (StringUtils.isNotBlank(request.getLocationRefId())) {
            flow.location = db.get(Location.class, request.getLocationRefId());
        }
        if (StringUtils.isNotBlank(request.getFormula())) {
            flow.formula = request.getFormula();
        }
        if (StringUtils.isNotBlank(request.getSynonyms())) {
            flow.synonyms = request.getSynonyms();
        }

        // 持久化到数据库
        var dao = new FlowDao(db);
        var result = dao.insert(flow);
        db.close();

        return GlobalResponse.of(result.id);
    }

    @PostMapping("/addBatch")
    public GlobalResponse<Long> addBatch(@RequestBody FlowRequestList requestList) {

        log.info(JSONUtil.toJsonStr(requestList));

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        requestList.getFlowRequestList().forEach(request -> {
            Flow flow = Flow.product(
                    request.getName(),
                    db.get(FlowProperty.class, request.getFlowPropertyId())
            );

            flow.id = request.getId();
            flow.refId = request.getRefId();
            if (request.getInfrastructureFlow() != null) {
                flow.infrastructureFlow = request.getInfrastructureFlow();
            }
            if (StringUtils.isNotBlank(request.getDescription())) {
                flow.description = request.getDescription();
            }
            if (StringUtils.isNotBlank(request.getCasNumber())) {
                flow.casNumber = request.getCasNumber();
            }
            if (StringUtils.isNotBlank(request.getLocationRefId())) {
                flow.location = db.get(Location.class, request.getLocationRefId());
            }
            if (StringUtils.isNotBlank(request.getFormula())) {
                flow.formula = request.getFormula();
            }
            if (StringUtils.isNotBlank(request.getSynonyms())) {
                flow.synonyms = request.getSynonyms();
            }

            request.getPropertyFators().forEach((k, v) -> {
                if (!Objects.equals(k, request.getFlowPropertyId())) {
                    flow.flowPropertyFactors.add(FlowPropertyFactor.of(db.get(FlowProperty.class, k), v));
                } else {
                    flow.getFactor(db.get(FlowProperty.class, k)).conversionFactor = v;
                }
            });

            // 持久化到数据库
            var dao = new FlowDao(db);
            dao.insert(flow);
        });

        db.close();

        return GlobalResponse.success();
    }

    @PostMapping("/update")
    public GlobalResponse<Long> update(@RequestBody FlowRequest request) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        var dao = new FlowDao(db);

        Flow flow = dao.getForId(request.getId());

        flow.name = request.getName();
        // 设置必要属性
        flow.refId = request.getRefId();
        if (request.getInfrastructureFlow() != null) {
            flow.infrastructureFlow = request.getInfrastructureFlow();
        }
        if (StringUtils.isNotBlank(request.getDescription())) {
            flow.description = request.getDescription();
        }
        if (StringUtils.isNotBlank(request.getCasNumber())) {
            flow.casNumber = request.getCasNumber();
        }
        if (StringUtils.isNotBlank(request.getLocationRefId())) {
            flow.location = db.get(Location.class, request.getLocationRefId());
        }
        if (StringUtils.isNotBlank(request.getFormula())) {
            flow.formula = request.getFormula();
        }
        if (StringUtils.isNotBlank(request.getSynonyms())) {
            flow.synonyms = request.getSynonyms();
        }

        if (request.getFlowPropertyId() != null) {
            flow.referenceFlowProperty = db.get(FlowProperty.class, request.getFlowPropertyId());
        }
        // 持久化到数据库
        var result = dao.update(flow);
        db.close();

        return GlobalResponse.of(result.id);
    }

    @PostMapping("/addPropertyFators")
    public GlobalResponse<Long> addPropertyFators(@RequestBody PropertyFatorsRequest request) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        var dao = new FlowDao(db);

        Flow flow = dao.getForId(request.getFlowId());

        flow.referenceFlowProperty = db.get(FlowProperty.class, request.getDefaultPropertyId());

        flow.flowPropertyFactors.clear();

        request.getPropertyFators().forEach((k, v) -> flow.flowPropertyFactors.add(FlowPropertyFactor.of(db.get(FlowProperty.class, k), v)));

        // 持久化到数据库
        var result = dao.update(flow);
        db.close();

        return GlobalResponse.of(result.id);
    }

    @GetMapping("/delete/{id}")
    public GlobalResponse<String> delete(@PathVariable("id") String id) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        new FlowDao(db).delete(Long.parseLong(id));
        db.close();

        return GlobalResponse.success();
    }

    @GetMapping("/get/{refId}")
    public GlobalResponse<Flow> get(@PathVariable("refId") String refId) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        var dao = new FlowDao(db);
        Flow flow = dao.getForRefId(refId);
        db.close();
        flow.flowPropertyFactors.forEach(i -> {
            if (null != i.flowProperty) {
                i.flowProperty.unitGroup = null;
            }
        });
        if (null != flow.referenceFlowProperty) {
            flow.referenceFlowProperty.unitGroup = null;
        }
        return GlobalResponse.of(flow);
    }

    @GetMapping("/getAll")
    public GlobalResponse<List<Flow>> getAll() {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        var dao = new FlowDao(db);
        List<Flow> flows = dao.getAll();
        db.close();
        flows.forEach(flow -> {
            flow.flowPropertyFactors.forEach(f -> f.flowProperty.unitGroup = null);
            if (flow.referenceFlowProperty != null) {
                flow.referenceFlowProperty.unitGroup = null;
            }
        });
        return GlobalResponse.of(flows);
    }

}
